#include "MethodDEClassical.h"
#include "Problem.h"
#include "problem1.h"



MethodDEClassical::MethodDEClassical(Method::SubType subType, Problem * problem, unsigned int popSize, unsigned int iterations) :
    Method(subType, problem, popSize, iterations)
{
    setCr(0.5*(getProblem()->getDimention()));
}



MethodDEClassical::~MethodDEClassical() {}



OptimizedValue MethodDEClassical::optimize(int caseProblem)
{
    getProblem()->setFunction(caseProblem);

    OptimizedValue optValue;
    RandomLib::Random r;

    //INITIALIZATION

    int populationSize=getPopulationSize(), dim=getProblem()->getDimention();
    unsigned int i=0 ,j=0, bestFitted=0;

    std::vector<double> cost(populationSize,0);
    matrix population(populationSize, std::vector<double>(dim,0));
    population=initialize(population);
    matrix mutatedPopulation=population;

    //cost stores function value for each populationMember
    cost=initializeCost(population, cost);
    r.Reseed();

    for (i=0; i<getIterations(); i++)    {
        //find best fitted
        bestFitted=std::find(cost.begin(), cost.end(), (double) *min_element(cost.begin(), cost.end())) - cost.begin();
        //MUTATION
        for (j=0; j<populationSize; j++ ){
            //MUTATION
            mutation(population, mutatedPopulation, r, j, cost,i);
            //CROSSOVER
            if(j!=bestFitted)
                crossover(population, mutatedPopulation, r, j);
            cost[j]=getProblem()->computeValue(mutatedPopulation[j]);
        }//for choosing three population members loop
        population=mutatedPopulation;
    }//for main loop
    optValue.value=(double) *min_element(cost.begin(), cost.end());
    optValue.atPoint=population[std::find(cost.begin(), cost.end(), (double) *min_element(cost.begin(), cost.end())) - cost.begin()];
//     return (double) *min_element(cost.begin(), cost.end());
    return optValue;
}

void MethodDEClassical::mutation(matrix & population, matrix & mutatedPopulation, RandomLib::Random r, unsigned int j, std::vector<double> & cost, unsigned int i){
    //put that into structure and instead of initializing every time pass the structure
    int a=0, b=0, c=0, k=0;
    double val=0, comp=0, mutatedValue=0;
    int populationSize=getPopulationSize();//should be j not i//but it actually perform better if i put i here instead of j
    //i does not make vectors to converge into one wrong min
    //with i it implies diffrent mutation has different i value, so each iteration do mutation and for each mutation i is differentI
    //it actually does not slowed it down
    //something else what I changed last time

    //variables initialize every time mutation and crossoer is called
            do
            {
                a=r.IntegerC(1,populationSize)-1;
            }
            while(i==a);
            do
            {
                b=r.IntegerC(1,populationSize)-1;
            }
            while(b==i || b==a);
            do
            {
                c=r.IntegerC(1,populationSize)-1;
            }
            while(c==i || c==a || c==b);
            val=r.FloatN()*(getProblem()->getDimention());
            if(val<cr+0.2)
            {
                for(k=0; k<getProblem()->getDimention(); k++)
                {
                    mutatedValue=population[c][k]+population[a][k]-population[b][k];
                    if((getProblem()->getCoordinates()[k].getUpperBound()>=mutatedValue)&&(getProblem()->getCoordinates()[k].getLowerBound()<=mutatedValue))
                        mutatedPopulation[j][k]=mutatedValue;
                    else
                        mutatedPopulation[j][k]=population[j][k];
                }
                //here computed val not coresponding
                comp=getProblem()->computeValue(mutatedPopulation[j]);
                if(cost[j]>comp)
                {
                    population[j]=mutatedPopulation[j];
                    cost[j]=comp;
                }
            }
            else
                for(k=0; k<getProblem()->getDimention(); k++)
                {
                    mutatedPopulation[j][k]=population[j][k];
                }

}

//j is an iterator for population(generation)=>one member at a time
void MethodDEClassical::crossover(matrix & population, matrix & mutatedPopulation, RandomLib::Random r, unsigned int j)
{
    unsigned int k;
    double val;
    for(k=0; k<getProblem()->getDimention(); k++)
    {
        val=r.FloatN()*(getProblem()->getDimention());
        if(val<cr+0.2)
        {
//                    k=r.IntegerC(1,dim)-1;
            mutatedPopulation[j][k]=population[j][k];

        }
    }

}
